package com.yhb.controller;

import com.yhb.channel.ChannelDispatcher;
import com.yhb.channel.model.TryBindRemitCardException;
import com.yhb.conf.ResultCode;
import com.yhb.controller.form.WithdrawForm;
import com.yhb.controller.vo.ArrayWrapperVo;
import com.yhb.controller.vo.SingleValueWrapVo;
import com.yhb.model.BalanceFlow;
import com.yhb.model.RapidCheat;
import com.yhb.model.User;
import com.yhb.model.WithdrawFlow;
import com.yhb.service.BalanceService;
import com.yhb.service.CardService;
import com.yhb.yinsheng.UnionPayService;
import lombok.extern.log4j.Log4j;
import lombok.var;
import me.edzh.spring.bootstrap.annotations.CurrentUser;
import me.edzh.spring.bootstrap.annotations.EncryptedRequestBody;
import me.edzh.spring.bootstrap.annotations.NeedAuth;
import me.edzh.spring.bootstrap.annotations.SignedRequestBody;
import me.edzh.spring.bootstrap.controller.BaseController;
import me.edzh.spring.bootstrap.model.HashMapWrapper;
import me.edzh.spring.bootstrap.model.Response;
import me.edzh.spring.bootstrap.utils.Constants;
import me.edzh.spring.bootstrap.utils.exception.ServiceException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;

import java.math.BigDecimal;
import java.util.*;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.stream.Collectors;

@Log4j
@RestController
@RequestMapping("/balance")
public class BalanceController extends BaseController {
    @Autowired
    private BalanceService balanceService;

    @Autowired
    private UnionPayService unionPayService;

    @Autowired
    private ChannelDispatcher channelDispatcher;

    @Autowired
    private CardService cardService;


    @GetMapping("/incomeFlows")
    @NeedAuth
    public Response<ArrayWrapperVo<BalanceFlow>> balanceFlow(@CurrentUser User user) {
        var result = balanceService.balanceList(user.getId());
        return new Response<>(new ArrayWrapperVo<>(result));
    }

    @GetMapping("/summary")
    @NeedAuth
    public Response<ArrayWrapperVo<BalanceFlow>> getBalanceSummary(@CurrentUser User user) {
        return new Response<>(new ArrayWrapperVo<>(balanceService.getUserBalanceTyped(user.getId())));
    }

    @PostMapping("/withdraw")
    @NeedAuth
    public Response withdraw(@EncryptedRequestBody WithdrawForm form, @CurrentUser User user) {
        balanceService.commitWithDraw(user, form.getAmount(), form.getType(), form.getCardId());
        return Response.ok();
    }

    @GetMapping("/withdrawFlows")
    @NeedAuth
    public Response<ArrayWrapperVo<WithdrawFlow>> getWithdrawFlows(@CurrentUser User user) {
        return Response.ok(new ArrayWrapperVo<>(balanceService.withdrawList(user.getId())));
    }
    @GetMapping("/lifeTimeIncome")
    @NeedAuth
    public Response<SingleValueWrapVo<BigDecimal>> getLifeTimeIncome(@CurrentUser User user) {
        return Response.ok(new SingleValueWrapVo<>(balanceService.userLifeTimeIncome(user.getId())));
    }

    @PostMapping("/reserve/{type}/query")
    @NeedAuth
    public Response<ArrayWrapperVo<BalanceFlow>> queryReserveBalance(@SignedRequestBody HashMapWrapper map, @CurrentUser User user, @PathVariable("type") String type) {
        if (RapidCheat.Type.UNION_PAY_CHANNEL.name().equals(type)) {
            var balance = unionPayService.queryBalance(user);
            return Response.ok(new ArrayWrapperVo<>(Arrays.asList(BalanceFlow.builder()
                    .amount(processBalance(balance))
                    .additionalInfos(RapidCheat.Type.UNION_PAY_CHANNEL.name())
                    .description(new HashMap<String, String>() {{
                        put("channelName", "银联闪付");
                    }})
                    .build())));
        } else {
            if (RapidCheat.Type.COMMON_CHANNEL.name().equals(type)) {
                var balances = channelDispatcher.queryUserBalance(user.getId());
                AtomicInteger idx = new AtomicInteger(0);
                return Response.ok(new ArrayWrapperVo<>(balances.parallelStream()
                        .filter(b -> b.getBalance().compareTo(BigDecimal.valueOf(20)) > 0)
                        .map(b -> BalanceFlow.builder()
                                        .amount(processBalance(b.getBalance()))
                                        .additionalInfos(b.getChannelType())
                                        .description(new HashMap<String, String>() {{
                                            put("channelName", "通道-" + idx.incrementAndGet() + "余额");
                                        }})
                                        .build()
                        )
                        .sorted(Comparator.comparing(BalanceFlow::getAmount).reversed())
                        .limit(3)
                        .collect(Collectors.toList())
                ));

            }
        }
        throw new ServiceException(ResultCode.ERROR_PARAMETER_WRONG, "FUCKU");
    }

    @PostMapping("/reserve/{channelId}/withdraw")
    @NeedAuth
    public Response withdrawReverseBalance(@EncryptedRequestBody WithdrawForm withdrawForm, @CurrentUser User user, @PathVariable("channelId") String channelId) {
        var now = new Date();
        if (now.getHours() >= 9 && now.getHours() < 22) throw new ServiceException(ResultCode.ERROR_TOAST_ERR, "请在22:00至次日9:00发起提现");


        if (RapidCheat.Type.UNION_PAY_CHANNEL.name().equals(channelId)) {
            unionPayService.activeWithdrawAllReserveBalance(user, withdrawForm.getCardId(), withdrawForm.getAmount());
        } else {
            if (BigDecimal.valueOf(20).compareTo(withdrawForm.getAmount()) >= 0) {
                throw new ServiceException(ResultCode.ERROR_TOAST_ERR, "提现金额过小");
            }
            try {
              channelDispatcher.tryRemit(channelId,
                        user,
                        cardService.cardWithOwnerCheck(withdrawForm.getCardId(), user.getId()),
                        null,
                        withdrawForm.getAmount().subtract(new BigDecimal("2")),
                        BigDecimal.valueOf(1.),
                        Constants.getCurrentRemoteIp(),
                        "0",
                        "",
                        "",
                        "");
            } catch (TryBindRemitCardException ignored) {

            }
        }
        return Response.ok();
    }


    private BigDecimal processBalance(BigDecimal balance) {
        if (balance.compareTo(new BigDecimal("20")) <= 0) {
            balance = BigDecimal.ZERO;
        }

        return balance;
    }
}
